package com.deyuanyun.pic.pipe.dao;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.stereotype.Service;

import com.deyuanyun.pic.common.spring.SpringAppliction;
import com.deyuanyun.pic.common.util.StringUtils;


@Service
public class BaseDAOImpl implements BaseDAO {

    //Spring创建对象的时候，就会往里面放实体类和它所对应的Mapper
    //private @Resource MapperBeanPostPrcessorImpl mapperBeanPostPrcessorImpl;
    //private Map<Class<?>,Object> mapperMap = new HashMap<Class<?>, Object>();
    
    //Mapper、方法名、方法对象（把Method存起来，效率好一些）
    private Map<Class<?>,Map<String,Method>> map = new HashMap<Class<?>, Map<String,Method>>();
    
    
    
    
    @Override
    public <T> T queryObjectByPrimaryKey(Class<T> clazz, String primaryKey) {
        if(StringUtils.isEmpty(primaryKey)){
            return null;
        }
        List<T> list = selectByExample(clazz,"id",primaryKey);
        if(list == null || list.isEmpty()){
            return null;
        }else{
            return list.get(0);
        }
    }

    @Override
    public <T> T queryObjectByCustomNumber(Class<T> clazz, String customNumber) {
        
        if(StringUtils.isEmpty(customNumber)){
            return null;
        }
        String[] fieldNames = new String[]{"customNumber","isNewest","deleted"};
        Object[] fieldValues = new Object[]{customNumber,(short)0,(short)0};
        
        List<T> list = selectByExample(clazz,fieldNames,fieldValues);
        if(list == null || list.isEmpty()){
            return null;
        }else{
            return list.get(0);
        }
    }

    @Override
    public int insert(Object record) {
        return exe("insert",record);
    }

    @Override
    public int insertSelective(Object record) {
        return exe("insertSelective",record);
    }

    @Override
    public int updateByPrimaryKeySelective(Object record) {
        return exe("updateByPrimaryKeySelective",record);
    }

    @Override
    public int updateByPrimaryKey(Object record) {
        return exe("updateByPrimaryKey",record);
    }

    public <T> List<T> selectByExample(Class<T> clazz,String fieldName,Object fieldValue){
        return selectByExample(clazz,new String[]{fieldName},new Object[]{fieldValue});
    }
    
    //这个反射调用不是那么科学，可以考虑动态代理、ASM这一类的。
    public <T> List<T> selectByExample(Class<T> clazz,String[] fieldNames,Object[] fieldValues){
        try {
            String methodName = "selectByExample";
            String methodName_createCriteria = "selectByExample_createCriteria";//创建条件的方法名称
            String methodName_criteria_where = "selectByExample_criteria_where";//字段的条件方法前缀
            String mapperName = StringUtils.toLowerCaseFirstOne(clazz.getSimpleName()) + "Mapper";
            Object mapper = SpringAppliction.getBean(mapperName);//clazz
            if(mapper == null){//获取Mapper对象
                return null;
            }
            
            Map<String,Method> methodMap = map.get(mapper.getClass());
            if(methodMap == null){//获取方法名和Method的MAP
                methodMap = new HashMap<String,Method>();
                map.put(mapper.getClass(), methodMap);
            }
            Method method = methodMap.get(methodName);
            if(method == null){//获取具体方法
                Method[] methods =  mapper.getClass().getMethods();
                for (int i = 0; i < methods.length; i++) {
                    //这种获取Method，我知道很糟糕，不过没想到别的方法，或许也可以拼接字符串获取参数类型。
                    Method m = methods[i];
                    if(methodName.equals(m.getName())){
                        method = m;
                        methodMap.put(methodName, method);    
                    }
                }
            }
            Object p1_1 = method.getParameterTypes()[0].newInstance();
            
            Method method_createCriteria = methodMap.get(methodName_createCriteria);
            if(method_createCriteria == null){//获取createCriteria方法
                method_createCriteria = p1_1.getClass().getMethod("createCriteria");
                methodMap.put(methodName_createCriteria, method_createCriteria);
            }
            Object obj_Criteria = method_createCriteria.invoke(p1_1);//创建条件对象Criteria
            for (int i = 0; i < fieldNames.length; i++) {
                String fieldName = fieldNames[i];
                Object fieldValue = fieldValues[i];
                Method method_criteria_where = methodMap.get(methodName_criteria_where + fieldName);
                if(method_criteria_where == null){//获取createCriteria方法
                    method_criteria_where = obj_Criteria.getClass().getMethod("and" + StringUtils.toUpperCaseFirstOne(fieldName) + "EqualTo",fieldValue.getClass());
                    methodMap.put(methodName_criteria_where + fieldName, method_criteria_where);
                }
                method_criteria_where.invoke(obj_Criteria, fieldValue);
            }
            @SuppressWarnings("unchecked")
            List<T> list = (List<T>)method.invoke(mapper, p1_1);
            
            return list;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    
    //这个反射调用不是那么科学，可以考虑动态代理、ASM这一类的。
    private int exe(String methodName,Object record){
        try {
            String mapperName = StringUtils.toLowerCaseFirstOne(record.getClass().getSimpleName()) + "Mapper";
            Object mapper = SpringAppliction.getBean(mapperName);//clazz
            if(mapper == null){
                return 0;
            }
            
            Map<String,Method> methodMap = map.get(mapper.getClass());
            if(methodMap == null){
                methodMap = new HashMap<String,Method>();
                map.put(mapper.getClass(), methodMap);
            }
            Method method = methodMap.get(methodName);
            if(method == null){
                method = mapper.getClass().getMethod(methodName, record.getClass());
                methodMap.put(methodName, method);
            }
            Object obj = method.invoke(mapper, record);
            return (Integer)obj;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
